#include "DataSensor.h"
#include "WSNNotifierConsts.h"
#include "IPv4Address.h"
#include "NotificationBoard.h"
#include "WSNIPProtocolld.h"
#include "LBTRPacket_m.h"
#include "DATAPacket_m.h"
#include "InterfaceTableAccess.h"
#include "IPv4InterfaceData.h"
#include "IPv4ControlInfo.h"

Define_Module(DataSensor);

DataSensor :: DataSensor() {

    status = APPLICATION_STOP_SENDING;
    isUp = true;
    baseStationAddr = IPv4Address::UNSPECIFIED_ADDRESS;
    numSent = 0;
    timer = NULL;
    xID = 0;
}

DataSensor :: ~DataSensor() {

}

void DataSensor :: initialize(int stage) {
    if (stage == 0) {

        WATCH(baseStationAddr);
        WATCH(numSent);
    }
    if (stage == 4) {
        ift = InterfaceTableAccess().get();
        ie = ift->getInterfaceByName("wlan0");
        nb = NotificationBoardAccess().get();
        nb->subscribe(this, APPLICATION_START_SENDING);
        nb->subscribe(this, APPLICATION_STOP_SENDING);
        nb->subscribe(this, APPLICATION_WAIT_SENDING);
        nb->subscribe(this, APPLICATION_CONTINUE_SENDING);
        nb->subscribe(this, APPLICATION_BASESTATION_ADDR_ACHIEVE);
        nb->subscribe(this, BATTERY_RESIDUAL_EMPTY);
    }
}

/*
 * @Function handleMessage
 * @Author Hien Hoang
 * @Version Nov 29, 2013
 * @Description
 * ||
 * */
void DataSensor :: handleMessage(cMessage *msg) {
    if (isUp == false) {

        delete msg;
        return;
    }

    if (msg->isSelfMessage()) {

        handleSelfMessage(msg);
    }
    else {
        // Receice message from lower not supported yet
        EV << "LBAPP: Not supported function, deleting message ..." << endl;
        delete msg;
    }
}

void DataSensor :: handleSelfMessage(cMessage *msg) {

    // Send data
    if (msg->getKind() == SEND_DATA) {
        // Send data
        DataPacket *pkt = new DataPacket("LBAPPdata");
        pkt->setDType(DATAREQ);
        pkt->setXID(xID++);
        pkt->setSrcAddr(ie->ipv4Data()->getIPAddress());
        pkt->setData("LBAPP: This is data....");
        IPv4ControlInfo *controlInfo = new IPv4ControlInfo();
        controlInfo->setDestAddr(baseStationAddr);
        controlInfo->setTimeToLive(15);
        controlInfo->setProtocol(IP_PROT_LBAPP);
        pkt->setControlInfo(controlInfo);
        send(pkt, "dataOut");

        // Restart timer
        scheduleTimer(SEND_DATA);
    }
}


void DataSensor :: cancelTimer() {

    if (timer != NULL)
    {
        cancelEvent(timer);
        delete timer;
    }
}

void DataSensor :: scheduleTimer(TIMER_TYPE type) {

    Enter_Method_Silent();
    timer = new cMessage("DATA", type);
    scheduleAt(simTime() + DATA_TIMER, timer);
}

void DataSensor :: startSending() {

    if (!baseStationAddr.isUnspecified()){

        status = APPLICATION_START_SENDING;
        scheduleTimer(SEND_DATA);
    }
    else {

        stopSending();
    }
}

void DataSensor :: stopSending() {

    status = APPLICATION_STOP_SENDING;
    cancelTimer();
}

void DataSensor :: waitSending() {

    status = APPLICATION_WAIT_SENDING;
    cancelTimer();
}

void DataSensor :: continueSending() {

    status = APPLICATION_CONTINUE_SENDING;
    scheduleTimer(SEND_DATA);
}

void DataSensor :: receiveChangeNotification(int category, const cObject *details) {

    switch(category) {
    case APPLICATION_BASESTATION_ADDR_ACHIEVE:
        EV << "Base station address achieve, prepairing to sending..." << endl;
        if (details) {
            cPolymorphic *detailsAux = const_cast<cPolymorphic*>(details);
            LBTRSetupPacket *pkt = dynamic_cast<LBTRSetupPacket *>(detailsAux);
            baseStationAddr = pkt->getBaseAddr();
        }
        break;
    case APPLICATION_START_SENDING:
        EV << "Application is starting to send data..." << endl;
        startSending();
        break;
    case APPLICATION_STOP_SENDING:
        EV << "Application is stop sending data !!!" << endl;
        stopSending();
        break;
    case APPLICATION_WAIT_SENDING:
        EV << "Application is waiting to send data !!!" << endl;
        waitSending();
        break;
    case APPLICATION_CONTINUE_SENDING:
        EV << "Application continuing to send data..." << endl;
        continueSending();
        break;
    case BATTERY_RESIDUAL_EMPTY:
        EV << "Battery exhausted, turning down application..." << endl;
        isUp = false;
        break;
    }
}
